import { _decorator, Component, Node, Vec3, Graphics, Color, UITransform, view } from 'cc';
import { ObstacleManager } from './ObstacleManager';
import { VisionObstacle } from './VisionObstacle';
const { ccclass, property } = _decorator;

/**
 * 战争迷雾网格系统
 * 
 * 功能：
 * 1. 管理战争迷雾的网格状态（未探索、可见、已探索）
 * 2. 处理迷雾的渐变效果
 * 3. 实现基于区域的脏矩形更新优化
 * 4. 支持视线阻挡检测
 * 5. 处理半透明障碍物的视觉效果
 * 
 * 优化：
 * 1. 使用脏区域管理，只更新发生变化的区域
 * 2. 区域化更新减少每帧计算量
 * 3. 渐变效果的平滑处理
 */
export enum FogState {
    UNEXPLORED = 0,  // 未探索
    VISIBLE = 1,     // 可见
    REMEMBERED = 2   // 已探索但当前不可见
}

@ccclass('FogGrid')
export class FogGrid extends Component {
    @property
    public cellSize: number = 5;

    @property
    public mapSize: Vec3 = new Vec3(100, 1, 100);

    @property(Graphics)
    private fogGraphics: Graphics | null = null;

    @property
    private fadeSpeed: number = 2;

    @property
    private updateInterval: number = 0.1;  // 添加更新间隔属性

    private gridSizeX: number = 0;
    private gridSizeY: number = 0;
    public readonly targetAlpha: number[][] = [];

    private fogStates: FogState[][] = [];
    private fogAlpha: number[][] = [];
    private dirtyRegions: Set<string> = new Set();
    private updateRegionSize: number = 4; // 每个更新区域的大小（格子数）

    private needsRedraw: boolean = false;  // 添加重绘标记

    start() {
        this.initFogGrid();
    }

    private initFogGrid() {
        this.gridSizeX = Math.ceil(this.mapSize.x / this.cellSize);
        this.gridSizeY = Math.ceil(this.mapSize.z / this.cellSize);

        // 初始化迷雾状态和透明度
        for (let x = 0; x < this.gridSizeX; x++) {
            this.fogStates[x] = [];
            this.fogAlpha[x] = [];
            this.targetAlpha[x] = [];
            for (let y = 0; y < this.gridSizeY; y++) {
                this.fogStates[x][y] = FogState.UNEXPLORED;
                this.fogAlpha[x][y] = 1.0;  // 完全不可见
                this.targetAlpha[x][y] = 1.0;
            }
        }
    }

    public markRegionDirty(x: number, y: number): void {
        const regionX = Math.floor(x / this.updateRegionSize);
        const regionY = Math.floor(y / this.updateRegionSize);
        this.dirtyRegions.add(`${regionX},${regionY}`);
    }

    update(dt: number) {
        if (this.dirtyRegions.size === 0) return;

        let needsRedraw = false;
        const regionsToUpdate = new Set(this.dirtyRegions);
        this.dirtyRegions.clear();

        for (const region of regionsToUpdate) {
            const [regionX, regionY] = region.split(',').map(Number);
            const startX = regionX * this.updateRegionSize;
            const startY = regionY * this.updateRegionSize;
            const endX = Math.min(startX + this.updateRegionSize, this.gridSizeX);
            const endY = Math.min(startY + this.updateRegionSize, this.gridSizeY);

            for (let x = startX; x < endX; x++) {
                for (let y = startY; y < endY; y++) {
                    if (this.fogAlpha[x][y] !== this.targetAlpha[x][y]) {
                        this.fogAlpha[x][y] = this.lerp(
                            this.fogAlpha[x][y],
                            this.targetAlpha[x][y],
                            dt * this.fadeSpeed
                        );
                        needsRedraw = true;

                        // 如果还没有完全过渡，标记为下一帧继续更新
                        if (Math.abs(this.fogAlpha[x][y] - this.targetAlpha[x][y]) > 0.01) {
                            this.markRegionDirty(x, y);
                        }
                    }
                }
            }
        }

        if (needsRedraw) {
            this.drawFog();
        }
    }

    private lerp(start: number, end: number, t: number): number {
        return start + (end - start) * Math.min(1, t);
    }

    public checkLineOfSight(from: Vec3, to: Vec3): number {
        // 检查是否有直接视线
        if (!ObstacleManager.instance.hasLineOfSight(from, to)) {
            return 0; // 完全阻挡
        }

        // 检查半透明障碍物的影响
        const obstacles = this.getObstaclesInLine(from, to);
        let visibility = 1;

        for (const obstacle of obstacles) {
            const visionObstacle = obstacle.getComponent(VisionObstacle);
            if (visionObstacle && !visionObstacle.isOpaque) {
                visibility *= (1 - visionObstacle.visionBlockFactor);
            }
        }

        return visibility;
    }

    private getObstaclesInLine(from: Vec3, to: Vec3): Node[] {
        const obstacles: Node[] = [];
        const direction = new Vec3();
        Vec3.subtract(direction, to, from);
        const distance = direction.length();
        direction.normalize();

        const steps = Math.ceil(distance / this.cellSize);
        const stepSize = distance / steps;

        for (let i = 1; i < steps; i++) {
            const checkPoint = new Vec3(
                from.x + direction.x * stepSize * i,
                from.y,
                from.z + direction.z * stepSize * i
            );

            const obstacle = ObstacleManager.instance.getClosestObstacle(checkPoint, this.cellSize);
            if (obstacle && !obstacles.includes(obstacle)) {
                obstacles.push(obstacle);
            }
        }

        return obstacles;
    }

    public updateVisibility(position: Vec3, viewRadius: number) {
        const centerX = Math.floor((position.x + this.mapSize.x / 2) / this.cellSize);
        const centerY = Math.floor((position.z + this.mapSize.z / 2) / this.cellSize);
        const radiusCells = Math.ceil(viewRadius / this.cellSize);

        for (let x = -radiusCells; x <= radiusCells; x++) {
            for (let y = -radiusCells; y <= radiusCells; y++) {
                const checkX = centerX + x;
                const checkY = centerY + y;

                if (checkX >= 0 && checkX < this.gridSizeX &&
                    checkY >= 0 && checkY < this.gridSizeY) {
                    const cellCenter = this.getCellCenter(checkX, checkY);
                    const distance = Math.sqrt(x * x + y * y) * this.cellSize;

                    if (distance <= viewRadius) {
                        // 检查视线阻挡
                        const visibility = this.checkLineOfSight(position, cellCenter);
                        
                        if (visibility > 0) {
                            this.fogStates[checkX][checkY] = FogState.VISIBLE;
                            this.targetAlpha[checkX][checkY] = 1 - visibility;
                        } else if (this.fogStates[checkX][checkY] === FogState.VISIBLE) {
                            this.fogStates[checkX][checkY] = FogState.REMEMBERED;
                            this.targetAlpha[checkX][checkY] = 0.5;
                        }
                    }

                    // 标记受影响的区域为脏区域
                    this.markRegionDirty(checkX, checkY);
                }
            }
        }
    }

    private getCellCenter(gridX: number, gridY: number): Vec3 {
        return new Vec3(
            (gridX - this.gridSizeX / 2) * this.cellSize + this.cellSize / 2,
            0,
            (gridY - this.gridSizeY / 2) * this.cellSize + this.cellSize / 2
        );
    }

    private drawFog() {
        if (!this.fogGraphics) return;

        this.fogGraphics.clear();

        for (let x = 0; x < this.gridSizeX; x++) {
            for (let y = 0; y < this.gridSizeY; y++) {
                const alpha = this.fogAlpha[x][y];
                if (alpha > 0) {
                    const worldX = x * this.cellSize - this.mapSize.x / 2;
                    const worldY = y * this.cellSize - this.mapSize.z / 2;

                    this.fogGraphics.fillColor = new Color(0, 0, 0, alpha);
                    this.fogGraphics.rect(worldX, worldY, this.cellSize, this.cellSize);
                    this.fogGraphics.fill();
                }
            }
        }
    }

    public isCellVisible(position: Vec3): boolean {
        const gridX = Math.floor((position.x + this.mapSize.x / 2) / this.cellSize);
        const gridY = Math.floor((position.z + this.mapSize.z / 2) / this.cellSize);

        if (gridX >= 0 && gridX < this.gridSizeX &&
            gridY >= 0 && gridY < this.gridSizeY) {
            return this.fogStates[gridX][gridY] === FogState.VISIBLE;
        }

        return false;
    }

    public isCellExplored(position: Vec3): boolean {
        const gridX = Math.floor((position.x + this.mapSize.x / 2) / this.cellSize);
        const gridY = Math.floor((position.z + this.mapSize.z / 2) / this.cellSize);

        if (gridX >= 0 && gridX < this.gridSizeX &&
            gridY >= 0 && gridY < this.gridSizeY) {
            return this.fogStates[gridX][gridY] !== FogState.UNEXPLORED;
        }

        return false;
    }

    public updateCellVisibility(position: Vec3, visibility: number): void {
        const gridX = Math.floor((position.x + this.mapSize.x / 2) / this.cellSize);
        const gridY = Math.floor((position.z + this.mapSize.z / 2) / this.cellSize);
        const gridSize = this.getGridSize();

        if (gridX >= 0 && gridX < gridSize.x &&
            gridY >= 0 && gridY < gridSize.y) {
            this.targetAlpha[gridX][gridY] = 1 - visibility;
            this.markRegionDirty(gridX, gridY);
        }
    }

    public getGridSize(): { x: number, y: number } {
        return {
            x: this.gridSizeX,
            y: this.gridSizeY
        };
    }

    public getCellsInRadius(position: Vec3, radius: number): Vec3[] {
        const cells: Vec3[] = [];
        const cellRadius = Math.ceil(radius / this.cellSize);

        const centerX = Math.floor((position.x + this.mapSize.x / 2) / this.cellSize);
        const centerY = Math.floor((position.z + this.mapSize.z / 2) / this.cellSize);

        for (let x = -cellRadius; x <= cellRadius; x++) {
            for (let y = -cellRadius; y <= cellRadius; y++) {
                if (x * x + y * y <= cellRadius * cellRadius) {
                    const checkX = centerX + x;
                    const checkY = centerY + y;

                    if (checkX >= 0 && checkX < this.gridSizeX &&
                        checkY >= 0 && checkY < this.gridSizeY) {
                        const worldX = (checkX * this.cellSize) - this.mapSize.x / 2;
                        const worldZ = (checkY * this.cellSize) - this.mapSize.z / 2;
                        cells.push(new Vec3(worldX, 0, worldZ));
                    }
                }
            }
        }

        return cells;
    }

    public updateRegion(x: number, y: number): void {
        const startX = x * this.updateRegionSize;
        const startY = y * this.updateRegionSize;
        const endX = Math.min(startX + this.updateRegionSize, this.gridSizeX);
        const endY = Math.min(startY + this.updateRegionSize, this.gridSizeY);

        for (let gridX = startX; gridX < endX; gridX++) {
            for (let gridY = startY; gridY < endY; gridY++) {
                this.updateCell(gridX, gridY);
            }
        }
    }

    private updateCell(x: number, y: number): void {
        // 更新单个格子的状态
        if (this.fogAlpha[x][y] !== this.targetAlpha[x][y]) {
            const delta = this.fadeSpeed * this.updateInterval;
            if (this.fogAlpha[x][y] < this.targetAlpha[x][y]) {
                this.fogAlpha[x][y] = Math.min(
                    this.fogAlpha[x][y] + delta,
                    this.targetAlpha[x][y]
                );
            } else {
                this.fogAlpha[x][y] = Math.max(
                    this.fogAlpha[x][y] - delta,
                    this.targetAlpha[x][y]
                );
            }
            this.needsRedraw = true;
        }
    }
} 